package views;

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import model.Problem;
import model.Solution;
import model.SolverEnvironment;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.time.DynamicTimeSeriesCollection;
import org.jfree.data.time.Second;
import org.jfree.data.xy.XYDataset;
import util.Importer;
import util.SolutionImporter;
import views.VisualizeApplet.MachineOrderType;

public class VisualizeJFrame extends JFrame {

	public static void main(String[] args) {
		Importer importer = new Importer("datasets//model_a1_2.txt");
		importer.readData();
		Problem problem = importer.getProblem();
		SolutionImporter solutionImporter = new SolutionImporter(problem);
		solutionImporter.setSolutionFileName("solutions//assignment_a1_2.txt");

		Solution solution1 = solutionImporter.readData();
		solutionImporter = new SolutionImporter(problem);
		solutionImporter
				.setSolutionFileName("solutions//BestPhaseA/result_a1_2.txt");
		Solution solution2 = solutionImporter.readData();
		problem.createMachinesOrderedListsByLocationAndNeighborhood();
		solution2.refreshLoadCostContribution();
		solution2.refreshBalanceCostContribution();
		VisualizeJFrame app = new VisualizeJFrame(problem, solution1,
				solution2, 0L);
	}

	JPanel processingPanel;
	JPanel processingPanel2;
	VisualizeApplet sketch;
	VisualizeLoadCostApplet loadCostContributionApplet;
	VisualizeBalanceCostApplet balanceCostContributionApplet;

	DynamicTimeSeriesCollection dataset;
	JFreeChart chart;
	ChartPanel chartPanel;
	Timer timer;
	final long initial_cost;
	boolean hasBalanceObjective = false;

	List<Long> costValues = new ArrayList<Long>();

	public VisualizeJFrame(Problem problem, Solution initial_solution,
			Solution new_solution, long ic) {
		super("Visualizer");
		new_solution.refreshLoadCostContribution();
		new_solution.refreshBalanceCostContribution();
		this.initial_cost = ic;
		costValues.add(ic);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
		GridBagLayout layout = new GridBagLayout();
		GridBagConstraints c = new GridBagConstraints();
		this.setLayout(layout);
		processingPanel = new JPanel();
		// processingPanel.setBounds(20, 20, 600, 600);
		sketch = new VisualizeApplet(problem, initial_solution, new_solution,
				MachineOrderType.NEIGHBORHOOD);
		// sketch = new VisualizeApplet(problem, initial_solution, new_solution,
		// MachineOrderType.LOCATION);
		processingPanel.add(sketch);
		c.gridx = 0;
		c.gridy = 2;
		this.add(processingPanel, c);
		sketch.init();

		SolverEnvironment env = new SolverEnvironment(problem,
				initial_solution, new_solution);
		processingPanel2 = new JPanel(new GridBagLayout());
		// processingPanel2.setBounds(20, 20, 600, 600);
		loadCostContributionApplet = new VisualizeLoadCostApplet(env);
		c.gridx = 0;
		c.gridy = 0;
		processingPanel2.add(new JLabel("Load Cost"), c);
		c.gridx = 0;
		c.gridy = 1;
		processingPanel2.add(loadCostContributionApplet, c);
		hasBalanceObjective = problem.hasBalanceObjectives();
		if (hasBalanceObjective) {
			balanceCostContributionApplet = new VisualizeBalanceCostApplet(env);
			c.gridx = 0;
			c.gridy = 2;
			processingPanel2.add(new JLabel("Balance Cost"), c);
			c.gridx = 0;
			c.gridy = 3;
			processingPanel2.add(balanceCostContributionApplet, c);
			balanceCostContributionApplet.init();
		}
		c.gridx = 0;
		c.gridy = 1;
		this.add(processingPanel2, c);
		loadCostContributionApplet.init();

		dataset = new DynamicTimeSeriesCollection(1, 2 * 60, new Second());
		dataset.setTimeBase(new Second(0, 0, 0, 1, 1, 2011));

		dataset.addSeries(costData(), 0, "Cost");
		chart = createChart(dataset);
		chartPanel = new ChartPanel(chart);
		// chartPanel.addChartMouseListener(new ChartMouseListener() {
		// @Override
		// public void chartMouseClicked(ChartMouseEvent arg0) {
		// }
		//
		// @Override
		// public void chartMouseMoved(ChartMouseEvent arg0) {
		// }
		// });
		c.gridx = 0;
		c.gridy = 0;
		this.add(chartPanel, c);
		timer = new Timer(1000, new ActionListener() {
			float[] newData = new float[1];

			public void actionPerformed(ActionEvent e) {
				newData[0] = costValues.get(costValues.size() - 1).floatValue();
				dataset.advanceTime();
				dataset.appendData(newData);
			}
		});

		this.pack();
		this.setLocationRelativeTo(null);
		this.setVisible(true);
		timer.start();
		timer.setDelay(500);
	}

	private float[] costData() {
		float[] a = new float[2 * 60];
		for (int i = 0; i < a.length; i++) {
			a[i] = initial_cost;
		}
		return a;
	}

	private JFreeChart createChart(final XYDataset dataset) {
		final JFreeChart result = ChartFactory.createTimeSeriesChart(
				"COST BY TIME", "Time", "Cost", dataset, true, true, false);
		final XYPlot plot = result.getXYPlot();
		ValueAxis domain = plot.getDomainAxis();
		domain.setAutoRange(true);

		ValueAxis range = plot.getRangeAxis();
		range.setRange(0.0, (new Long(initial_cost).doubleValue()));
		return result;
	}

	public void setCurrentSolution(Solution current_solution) {
		sketch.setSolution2(current_solution);
		sketch.redraw();
		loadCostContributionApplet.setCurrentSolution(current_solution);
		current_solution.refreshLoadCostContribution();
		loadCostContributionApplet.redraw();
		if (hasBalanceObjective) {
			balanceCostContributionApplet.setCurrentSolution(current_solution);
			current_solution.refreshBalanceCostContribution();
			balanceCostContributionApplet.redraw();
		}
	}

	public void setMessage(String messageInVisualizer) {
		sketch.setMessage(messageInVisualizer);
		sketch.redraw();
	}

	public void setSelectedProcesses(List<Integer> selectedProcesses) {
		sketch.setSelectedProcesses(selectedProcesses);

	}

	long min = Long.MAX_VALUE;

	public void setCostValue(long cost) {
		long lower = 0, upper = 0;
		costValues.add(cost);
		if (cost < min)
			min = cost;
		lower = min;
		float lf = (float) lower;
		lf *= 0.999;
		long max_of_last_20_values = Integer.MIN_VALUE;
		int N = costValues.size() < 20 ? costValues.size() : 20;
		for (int i = 0; i < N; i++) {
			long v = costValues.get(costValues.size() - i - 1);
			if (v > max_of_last_20_values) {
				max_of_last_20_values = v;
			}
		}
		upper = max_of_last_20_values;
		float uf = (float) upper;
		uf *= 1.001;
		chart.getXYPlot().getRangeAxis().setRange(lf, uf);
	}

	public void closeWindow() {
		this.dispose();

	}
}
